Change signatures for gdk_drag_begin() and gdk_drag_motion() so that the
authorOwen Taylor <otaylor@redhat.com>
Thu, 28 Jan 1999 01:03:15 +0000 (01:03 +0000)
committerOwen Taylor <otaylor@src.gnome.org>
Thu, 28 Jan 1999 01:03:15 +0000 (01:03 +0000)
Wed Jan 27 18:57:57 1999  Owen Taylor  <otaylor@redhat.com>

* gdk/gdk.h gdk/gdkdnd.c: Change signatures for
gdk_drag_begin() and gdk_drag_motion() so that the set
of possible actions is passed on each motion, not just at
the beginning of the drag. We do this so that
we can restrict the set of possible drag events
when the user presses a modifier key during a
drag.

* gdk/gdkdnd.c: Send a motif Operation-changed
message when the set of possible actions change,
as well as when the suggested action change.

* gdk/gdkdnd.c: Change the XdndActionList whenever
the set of actions change.

* gdk/gdkdnd.c: Add a filter to catch changes to
the XdndActionList property for the source widget.

* gtk/gtkdnd.c: Change the set of possible actions
when the user presses Control, Shift, or Control-Shift,
to only include the corresponding action.

* gtk/gtkdnd.c (gtk_drag_button_release_cb):
Disconnect button signals before we possibly
free info structure.

ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
gdk/gdk.h
gdk/gdkdnd.c
gdk/x11/gdkdnd-x11.c
gtk/gtkdnd.c

index 2b4f3123715e41e683f0a55e9332eab021456c7b..899805c7b527b6348dfb53750327feb45c0128b9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
+Wed Jan 27 20:06:06 1999  Owen Taylor  <otaylor@redhat.com>
+
+       * gtk/gtklayout.c (gtk_layout_adjustment_changed):
+       Removed some g_print()'s
+
+Wed Jan 27 18:57:57 1999  Owen Taylor  <otaylor@redhat.com>
+
+       * gdk/gdk.h gdk/gdkdnd.c: Change signatures for 
+       gdk_drag_begin() and gdk_drag_motion() so that the set 
+       of possible actions is passed on each motion, not just at
+       the beginning of the drag. We do this so that
+       we can restrict the set of possible drag events
+       when the user presses a modifier key during a 
+       drag.
+
+       * gdk/gdkdnd.c: Send a motif Operation-changed
+       message when the set of possible actions change,
+       as well as when the suggested action change.
+
+       * gdk/gdkdnd.c: Change the XdndActionList whenever
+       the set of actions change.
+
+       * gdk/gdkdnd.c: Add a filter to catch changes to
+       the XdndActionList property for the source widget.
+
+       * gtk/gtkdnd.c: Change the set of possible actions
+       when the user presses Control, Shift, or Control-Shift,
+       to only include the corresponding action.
+       
+       * gtk/gtkdnd.c (gtk_drag_button_release_cb):
+       Disconnect button signals before we possibly
+       free info structure.
+
 Wed Jan 27 18:40:50 1999  Owen Taylor  <otaylor@redhat.com>
 
        * gtk/gtkmain.c (gtk_main_do_event): Hack scrollwheel
index 2b4f3123715e41e683f0a55e9332eab021456c7b..899805c7b527b6348dfb53750327feb45c0128b9 100644 (file)
@@ -1,3 +1,36 @@
+Wed Jan 27 20:06:06 1999  Owen Taylor  <otaylor@redhat.com>
+
+       * gtk/gtklayout.c (gtk_layout_adjustment_changed):
+       Removed some g_print()'s
+
+Wed Jan 27 18:57:57 1999  Owen Taylor  <otaylor@redhat.com>
+
+       * gdk/gdk.h gdk/gdkdnd.c: Change signatures for 
+       gdk_drag_begin() and gdk_drag_motion() so that the set 
+       of possible actions is passed on each motion, not just at
+       the beginning of the drag. We do this so that
+       we can restrict the set of possible drag events
+       when the user presses a modifier key during a 
+       drag.
+
+       * gdk/gdkdnd.c: Send a motif Operation-changed
+       message when the set of possible actions change,
+       as well as when the suggested action change.
+
+       * gdk/gdkdnd.c: Change the XdndActionList whenever
+       the set of actions change.
+
+       * gdk/gdkdnd.c: Add a filter to catch changes to
+       the XdndActionList property for the source widget.
+
+       * gtk/gtkdnd.c: Change the set of possible actions
+       when the user presses Control, Shift, or Control-Shift,
+       to only include the corresponding action.
+       
+       * gtk/gtkdnd.c (gtk_drag_button_release_cb):
+       Disconnect button signals before we possibly
+       free info structure.
+
 Wed Jan 27 18:40:50 1999  Owen Taylor  <otaylor@redhat.com>
 
        * gtk/gtkmain.c (gtk_main_do_event): Hack scrollwheel
index 2b4f3123715e41e683f0a55e9332eab021456c7b..899805c7b527b6348dfb53750327feb45c0128b9 100644 (file)
@@ -1,3 +1,36 @@
+Wed Jan 27 20:06:06 1999  Owen Taylor  <otaylor@redhat.com>
+
+       * gtk/gtklayout.c (gtk_layout_adjustment_changed):
+       Removed some g_print()'s
+
+Wed Jan 27 18:57:57 1999  Owen Taylor  <otaylor@redhat.com>
+
+       * gdk/gdk.h gdk/gdkdnd.c: Change signatures for 
+       gdk_drag_begin() and gdk_drag_motion() so that the set 
+       of possible actions is passed on each motion, not just at
+       the beginning of the drag. We do this so that
+       we can restrict the set of possible drag events
+       when the user presses a modifier key during a 
+       drag.
+
+       * gdk/gdkdnd.c: Send a motif Operation-changed
+       message when the set of possible actions change,
+       as well as when the suggested action change.
+
+       * gdk/gdkdnd.c: Change the XdndActionList whenever
+       the set of actions change.
+
+       * gdk/gdkdnd.c: Add a filter to catch changes to
+       the XdndActionList property for the source widget.
+
+       * gtk/gtkdnd.c: Change the set of possible actions
+       when the user presses Control, Shift, or Control-Shift,
+       to only include the corresponding action.
+       
+       * gtk/gtkdnd.c (gtk_drag_button_release_cb):
+       Disconnect button signals before we possibly
+       free info structure.
+
 Wed Jan 27 18:40:50 1999  Owen Taylor  <otaylor@redhat.com>
 
        * gtk/gtkmain.c (gtk_main_do_event): Hack scrollwheel
index 2b4f3123715e41e683f0a55e9332eab021456c7b..899805c7b527b6348dfb53750327feb45c0128b9 100644 (file)
@@ -1,3 +1,36 @@
+Wed Jan 27 20:06:06 1999  Owen Taylor  <otaylor@redhat.com>
+
+       * gtk/gtklayout.c (gtk_layout_adjustment_changed):
+       Removed some g_print()'s
+
+Wed Jan 27 18:57:57 1999  Owen Taylor  <otaylor@redhat.com>
+
+       * gdk/gdk.h gdk/gdkdnd.c: Change signatures for 
+       gdk_drag_begin() and gdk_drag_motion() so that the set 
+       of possible actions is passed on each motion, not just at
+       the beginning of the drag. We do this so that
+       we can restrict the set of possible drag events
+       when the user presses a modifier key during a 
+       drag.
+
+       * gdk/gdkdnd.c: Send a motif Operation-changed
+       message when the set of possible actions change,
+       as well as when the suggested action change.
+
+       * gdk/gdkdnd.c: Change the XdndActionList whenever
+       the set of actions change.
+
+       * gdk/gdkdnd.c: Add a filter to catch changes to
+       the XdndActionList property for the source widget.
+
+       * gtk/gtkdnd.c: Change the set of possible actions
+       when the user presses Control, Shift, or Control-Shift,
+       to only include the corresponding action.
+       
+       * gtk/gtkdnd.c (gtk_drag_button_release_cb):
+       Disconnect button signals before we possibly
+       free info structure.
+
 Wed Jan 27 18:40:50 1999  Owen Taylor  <otaylor@redhat.com>
 
        * gtk/gtkmain.c (gtk_main_do_event): Hack scrollwheel
index 2b4f3123715e41e683f0a55e9332eab021456c7b..899805c7b527b6348dfb53750327feb45c0128b9 100644 (file)
@@ -1,3 +1,36 @@
+Wed Jan 27 20:06:06 1999  Owen Taylor  <otaylor@redhat.com>
+
+       * gtk/gtklayout.c (gtk_layout_adjustment_changed):
+       Removed some g_print()'s
+
+Wed Jan 27 18:57:57 1999  Owen Taylor  <otaylor@redhat.com>
+
+       * gdk/gdk.h gdk/gdkdnd.c: Change signatures for 
+       gdk_drag_begin() and gdk_drag_motion() so that the set 
+       of possible actions is passed on each motion, not just at
+       the beginning of the drag. We do this so that
+       we can restrict the set of possible drag events
+       when the user presses a modifier key during a 
+       drag.
+
+       * gdk/gdkdnd.c: Send a motif Operation-changed
+       message when the set of possible actions change,
+       as well as when the suggested action change.
+
+       * gdk/gdkdnd.c: Change the XdndActionList whenever
+       the set of actions change.
+
+       * gdk/gdkdnd.c: Add a filter to catch changes to
+       the XdndActionList property for the source widget.
+
+       * gtk/gtkdnd.c: Change the set of possible actions
+       when the user presses Control, Shift, or Control-Shift,
+       to only include the corresponding action.
+       
+       * gtk/gtkdnd.c (gtk_drag_button_release_cb):
+       Disconnect button signals before we possibly
+       free info structure.
+
 Wed Jan 27 18:40:50 1999  Owen Taylor  <otaylor@redhat.com>
 
        * gtk/gtkmain.c (gtk_main_do_event): Hack scrollwheel
index 2b4f3123715e41e683f0a55e9332eab021456c7b..899805c7b527b6348dfb53750327feb45c0128b9 100644 (file)
@@ -1,3 +1,36 @@
+Wed Jan 27 20:06:06 1999  Owen Taylor  <otaylor@redhat.com>
+
+       * gtk/gtklayout.c (gtk_layout_adjustment_changed):
+       Removed some g_print()'s
+
+Wed Jan 27 18:57:57 1999  Owen Taylor  <otaylor@redhat.com>
+
+       * gdk/gdk.h gdk/gdkdnd.c: Change signatures for 
+       gdk_drag_begin() and gdk_drag_motion() so that the set 
+       of possible actions is passed on each motion, not just at
+       the beginning of the drag. We do this so that
+       we can restrict the set of possible drag events
+       when the user presses a modifier key during a 
+       drag.
+
+       * gdk/gdkdnd.c: Send a motif Operation-changed
+       message when the set of possible actions change,
+       as well as when the suggested action change.
+
+       * gdk/gdkdnd.c: Change the XdndActionList whenever
+       the set of actions change.
+
+       * gdk/gdkdnd.c: Add a filter to catch changes to
+       the XdndActionList property for the source widget.
+
+       * gtk/gtkdnd.c: Change the set of possible actions
+       when the user presses Control, Shift, or Control-Shift,
+       to only include the corresponding action.
+       
+       * gtk/gtkdnd.c (gtk_drag_button_release_cb):
+       Disconnect button signals before we possibly
+       free info structure.
+
 Wed Jan 27 18:40:50 1999  Owen Taylor  <otaylor@redhat.com>
 
        * gtk/gtkmain.c (gtk_main_do_event): Hack scrollwheel
index 2b4f3123715e41e683f0a55e9332eab021456c7b..899805c7b527b6348dfb53750327feb45c0128b9 100644 (file)
@@ -1,3 +1,36 @@
+Wed Jan 27 20:06:06 1999  Owen Taylor  <otaylor@redhat.com>
+
+       * gtk/gtklayout.c (gtk_layout_adjustment_changed):
+       Removed some g_print()'s
+
+Wed Jan 27 18:57:57 1999  Owen Taylor  <otaylor@redhat.com>
+
+       * gdk/gdk.h gdk/gdkdnd.c: Change signatures for 
+       gdk_drag_begin() and gdk_drag_motion() so that the set 
+       of possible actions is passed on each motion, not just at
+       the beginning of the drag. We do this so that
+       we can restrict the set of possible drag events
+       when the user presses a modifier key during a 
+       drag.
+
+       * gdk/gdkdnd.c: Send a motif Operation-changed
+       message when the set of possible actions change,
+       as well as when the suggested action change.
+
+       * gdk/gdkdnd.c: Change the XdndActionList whenever
+       the set of actions change.
+
+       * gdk/gdkdnd.c: Add a filter to catch changes to
+       the XdndActionList property for the source widget.
+
+       * gtk/gtkdnd.c: Change the set of possible actions
+       when the user presses Control, Shift, or Control-Shift,
+       to only include the corresponding action.
+       
+       * gtk/gtkdnd.c (gtk_drag_button_release_cb):
+       Disconnect button signals before we possibly
+       free info structure.
+
 Wed Jan 27 18:40:50 1999  Owen Taylor  <otaylor@redhat.com>
 
        * gtk/gtkmain.c (gtk_main_do_event): Hack scrollwheel
index bae3ebb874077363d09ce7a99ddc62d0270187d0..34accf87c163c33e04701f3121539cf3cb3dd37a 100644 (file)
--- a/gdk/gdk.h
+++ b/gdk/gdk.h
@@ -262,8 +262,7 @@ GdkAtom          gdk_drag_get_selection (GdkDragContext   *context);
 /* Source side */
 
 GdkDragContext * gdk_drag_begin      (GdkWindow      *window,
-                                     GList          *targets,
-                                     GdkDragAction   actions);
+                                     GList          *targets);
 guint32         gdk_drag_get_protocol (guint32          xid,
                                       GdkDragProtocol *protocol);
 void             gdk_drag_find_window (GdkDragContext   *context,
@@ -277,7 +276,8 @@ gboolean        gdk_drag_motion      (GdkDragContext *context,
                                      GdkDragProtocol protocol,
                                      gint            x_root, 
                                      gint            y_root,
-                                     GdkDragAction   action,
+                                     GdkDragAction   suggested_action,
+                                     GdkDragAction   possible_actions,
                                      guint32         time);
 void            gdk_drag_drop        (GdkDragContext *context,
                                      guint32         time);
index 7c951e9869f7fe353ff849649eb3caa660e6448a..a4244bd35ce64019ea4b4db7d657754b0ac8d2aa 100644 (file)
@@ -56,11 +56,13 @@ struct _GdkDragContextPrivate {
 
   guint16 last_x;              /* Coordinates from last event */
   guint16 last_y;
-  GdkDragAction old_action;    /* The last action we sent to the source */
+  GdkDragAction old_action;      /* The last action we sent to the source */
+  GdkDragAction old_actions;     /* The last actions we sent to the source */
+  GdkDragAction xdnd_actions;     /* What is currently set in XdndActionList */
 
   Window  dest_xid;
   guint xdnd_targets_set : 1;   /* Whether we've already set XdndTypeList */
-  guint xdnd_actions_set : 1;   /* Whether we've already set XdndActionsList */
+  guint xdnd_actions_set : 1;   /* Whether we've already set XdndActionList */
   guint xdnd_have_actions : 1; /* Whether an XdndActionList was provided */
   guint motif_targets_set : 1;  /* Whether we've already set motif initiator info */
   guint drag_status : 4;       /* current status of drag */
@@ -103,6 +105,10 @@ static GdkFilterReturn xdnd_drop_filter (GdkXEvent *xev,
                                         GdkEvent  *event,
                                         gpointer   data);
 
+static void   xdnd_manage_source_filter (GdkDragContext *context,
+                                        GdkWindow      *window,
+                                        gboolean        add_filter);
+
 /* Drag Contexts */
 
 static GList *contexts;
@@ -145,7 +151,13 @@ gdk_drag_context_unref (GdkDragContext *context)
       g_list_free (context->targets);
 
       if (context->source_window)
-       gdk_window_unref (context->source_window);
+       {
+         if ((context->protocol == GDK_DRAG_PROTO_XDND) &&
+             !context->is_source)
+           xdnd_manage_source_filter (context, context->source_window, FALSE);
+
+         gdk_window_unref (context->source_window);
+       }
 
       if (context->dest_window)
        gdk_window_unref (context->dest_window);
@@ -1361,11 +1373,12 @@ motif_send_motion (GdkDragContext  *context,
   MOTIF_XCLIENT_SHORT (&xev, 1) = motif_dnd_get_flags (context);
   MOTIF_XCLIENT_LONG (&xev, 1) = time;
 
-  if (context->suggested_action != private->old_action)
+  if ((context->suggested_action != private->old_action) ||
+      (context->actions != private->old_actions))
     {
       MOTIF_XCLIENT_BYTE (&xev, 0) = XmOPERATION_CHANGED;
 
-      private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT;
+      /* private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT; */
       retval = TRUE;
     }
   else
@@ -1724,7 +1737,8 @@ motif_drag_status (GdkEvent *event,
   if (context)
     {
       GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
-      if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
+      if ((private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT) ||
+         (private->drag_status == GDK_DRAG_STATUS_ACTION_WAIT))
        private->drag_status = GDK_DRAG_STATUS_DRAG;
       
       event->dnd.type = GDK_DRAG_STATUS;
@@ -2009,7 +2023,7 @@ xdnd_set_actions (GdkDragContext *context)
 
   if (!xdnd_actions_initialized)
     xdnd_initialize_actions();
-
+  
   actions = context->actions;
   n_atoms = 0;
   for (i=0; i<xdnd_n_actions; i++)
@@ -2042,6 +2056,7 @@ xdnd_set_actions (GdkDragContext *context)
                   (guchar *)atomlist, n_atoms);
 
   private->xdnd_actions_set = 1;
+  private->xdnd_actions = context->actions;
 }
 
 static void
@@ -2082,9 +2097,6 @@ xdnd_send_enter (GdkDragContext *context)
        }
     }
 
-  if (!private->xdnd_actions_set)
-    xdnd_set_actions (context);
-
   if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
                        FALSE, 0, &xev))
     {
@@ -2256,6 +2268,133 @@ xdnd_check_dest (Window win)
 
 /* Target side */
 
+static void
+xdnd_read_actions (GdkDragContext *context)
+{
+  Atom type;
+  int format;
+  gulong nitems, after;
+  Atom *data;
+
+  gint i;
+
+  gint old_warnings = gdk_error_warnings;
+
+  gdk_error_code = 0;
+  gdk_error_warnings = 0;
+
+  /* Get the XdndActionList, if set */
+
+  XGetWindowProperty (GDK_WINDOW_XDISPLAY (context->source_window),
+                     GDK_WINDOW_XWINDOW (context->source_window),
+                     gdk_atom_intern ("XdndActionList", FALSE), 0, 65536,
+                     False, XA_ATOM, &type, &format, &nitems,
+                     &after, (guchar **)&data);
+  
+  if (!gdk_error_code && (format == 32) && (type == XA_ATOM))
+    {
+      context->actions = 0;
+
+      for (i=0; i<nitems; i++)
+       context->actions |= xdnd_action_from_atom (data[i]);
+
+      ((GdkDragContextPrivate *)context)->xdnd_have_actions = TRUE;
+
+#ifdef G_ENABLE_DEBUG
+      if (gdk_debug_flags & GDK_DEBUG_DND)
+       {
+         GString *action_str = g_string_new (NULL);
+         if (context->actions & GDK_ACTION_MOVE)
+           g_string_append(action_str, "MOVE ");
+         if (context->actions & GDK_ACTION_COPY)
+           g_string_append(action_str, "COPY ");
+         if (context->actions & GDK_ACTION_LINK)
+           g_string_append(action_str, "LINK ");
+         if (context->actions & GDK_ACTION_ASK)
+           g_string_append(action_str, "ASK ");
+         
+         g_message("Xdnd actions = %s", action_str->str);
+         g_string_free (action_str, TRUE);
+       }
+#endif /* G_ENABLE_DEBUG */
+
+      XFree(data);
+    }
+
+  gdk_error_warnings = old_warnings;
+  gdk_error_code = 0;
+}
+
+/* We have to make sure that the XdndActionList we keep internally
+ * is up to date with the XdndActionList on the source window
+ * because we get no notification, because Xdnd wasn't meant
+ * to continually send actions. So we select on PropertyChangeMask
+ * and add this filter.
+ */
+static GdkFilterReturn 
+xdnd_source_window_filter (GdkXEvent *xev,
+                          GdkEvent  *event,
+                          gpointer   cb_data)
+{
+  XEvent *xevent = (XEvent *)xev;
+  GdkDragContext *context = cb_data;
+
+  if ((xevent->xany.type == PropertyNotify) &&
+      (xevent->xproperty.atom == gdk_atom_intern ("XdndActionList", FALSE)))
+    {
+      xdnd_read_actions (context);
+
+      return GDK_FILTER_REMOVE;
+    }
+
+  return GDK_FILTER_CONTINUE;
+}
+
+static void
+xdnd_manage_source_filter (GdkDragContext *context,
+                          GdkWindow      *window,
+                          gboolean        add_filter)
+{
+  gint old_warnings = 0;       /* quiet gcc */
+  GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+                              
+  gboolean is_foreign = (private->window_type == GDK_WINDOW_FOREIGN);
+
+  if (is_foreign)
+    {
+      old_warnings = gdk_error_warnings;
+      gdk_error_warnings = 0;
+    }
+
+  if (!private->destroyed)
+    {
+      if (add_filter)
+       {
+         gdk_window_set_events (window,
+                                gdk_window_get_events (window) |
+                                GDK_PROPERTY_CHANGE_MASK);
+         gdk_window_add_filter (window, xdnd_source_window_filter, context);
+
+       }
+      else
+       {
+         gdk_window_remove_filter (window,
+                                   xdnd_source_window_filter,
+                                   context);
+         /* Should we remove the GDK_PROPERTY_NOTIFY mask?
+          * but we might want it for other reasons. (Like
+          * INCR selection transactions).
+          */
+       }
+    }
+
+  if (is_foreign)
+    {
+      gdk_flush();
+      gdk_error_warnings = old_warnings;
+    }
+}
+
 static GdkFilterReturn 
 xdnd_enter_filter (GdkXEvent *xev,
                   GdkEvent  *event,
@@ -2339,49 +2478,14 @@ xdnd_enter_filter (GdkXEvent *xev,
                                                GUINT_TO_POINTER (xevent->xclient.data.l[2+i]));
     }
 
-  /* Get the XdndActionList, if set */
-
-  XGetWindowProperty (GDK_WINDOW_XDISPLAY (event->any.window), 
-                     source_window, 
-                     gdk_atom_intern ("XdndActionList", FALSE), 0, 65536,
-                     False, XA_ATOM, &type, &format, &nitems,
-                     &after, (guchar **)&data);
-  
-  if ((format == 32) && (type == XA_ATOM))
-    {
-      new_context->actions = 0;
-
-      for (i=0; i<nitems; i++)
-       new_context->actions |= xdnd_action_from_atom (data[i]);
-
-      ((GdkDragContextPrivate *)new_context)->xdnd_have_actions = TRUE;
-
-#ifdef G_ENABLE_DEBUG
-      if (gdk_debug_flags & GDK_DEBUG_DND)
-       {
-         GString *action_str = g_string_new (NULL);
-         if (new_context->actions & GDK_ACTION_MOVE)
-           g_string_append(action_str, "MOVE ");
-         if (new_context->actions & GDK_ACTION_COPY)
-           g_string_append(action_str, "COPY ");
-         if (new_context->actions & GDK_ACTION_LINK)
-           g_string_append(action_str, "LINK ");
-         if (new_context->actions & GDK_ACTION_ASK)
-           g_string_append(action_str, "ASK ");
-         
-         g_message("\tactions = %s", action_str->str);
-         g_string_free (action_str, TRUE);
-       }
-#endif /* G_ENABLE_DEBUG */
-
-      XFree(data);
-    }
-  
 #ifdef G_ENABLE_DEBUG
   if (gdk_debug_flags & GDK_DEBUG_DND)
     print_target_list (new_context->targets);
 #endif /* G_ENABLE_DEBUG */
 
+  xdnd_manage_source_filter (new_context, new_context->source_window, TRUE);
+  xdnd_read_actions (new_context);
+
   event->dnd.type = GDK_DRAG_ENTER;
   event->dnd.context = new_context;
   gdk_drag_context_ref (new_context);
@@ -2558,8 +2662,7 @@ gdk_drag_do_leave (GdkDragContext *context, guint32 time)
 
 GdkDragContext * 
 gdk_drag_begin (GdkWindow     *window,
-               GList         *targets,
-               GdkDragAction  actions)
+               GList         *targets)
 {
   GList *tmp_list;
   GdkDragContext *new_context;
@@ -2580,7 +2683,7 @@ gdk_drag_begin (GdkWindow     *window,
       tmp_list = tmp_list->prev;
     }
 
-  new_context->actions = actions;
+  new_context->actions = 0;
 
   return new_context;
 }
@@ -2717,13 +2820,25 @@ gdk_drag_motion (GdkDragContext *context,
                 GdkDragProtocol protocol,
                 gint            x_root, 
                 gint            y_root,
-                GdkDragAction   action,
+                GdkDragAction   suggested_action,
+                GdkDragAction   possible_actions,
                 guint32         time)
 {
   GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
 
   g_return_val_if_fail (context != NULL, FALSE);
 
+  /* When we have a Xdnd target, make sure our XdndActionList
+   * matches the current actions;
+   */
+  private->old_actions = context->actions;
+  context->actions = possible_actions;
+  
+  if ((protocol == GDK_DRAG_PROTO_XDND) &&
+      (!private->xdnd_actions_set ||
+       private->xdnd_actions != possible_actions))
+    xdnd_set_actions (context);
+
   if (context->dest_window != dest_window)
     {
       GdkEvent temp_event;
@@ -2754,8 +2869,9 @@ gdk_drag_motion (GdkDragContext *context,
            case GDK_DRAG_PROTO_NONE:
              break;
            }
-         private->old_action = action;
-         context->suggested_action = action;
+         private->old_action = suggested_action;
+         context->suggested_action = suggested_action;
+         private->old_actions = possible_actions;
        }
       else
        {
@@ -2782,7 +2898,7 @@ gdk_drag_motion (GdkDragContext *context,
   else
     {
       private->old_action = context->suggested_action;
-      context->suggested_action = action;
+      context->suggested_action = suggested_action;
     }
 
   /* Send a drag-motion event */
@@ -2797,11 +2913,11 @@ gdk_drag_motion (GdkDragContext *context,
          switch (context->protocol)
            {
            case GDK_DRAG_PROTO_MOTIF:
-             motif_send_motion (context, x_root, y_root, action, time);
+             motif_send_motion (context, x_root, y_root, suggested_action, time);
              break;
              
            case GDK_DRAG_PROTO_XDND:
-             xdnd_send_motion (context, x_root, y_root, action, time);
+             xdnd_send_motion (context, x_root, y_root, suggested_action, time);
              break;
 
            case GDK_DRAG_PROTO_ROOTWIN:
index 7c951e9869f7fe353ff849649eb3caa660e6448a..a4244bd35ce64019ea4b4db7d657754b0ac8d2aa 100644 (file)
@@ -56,11 +56,13 @@ struct _GdkDragContextPrivate {
 
   guint16 last_x;              /* Coordinates from last event */
   guint16 last_y;
-  GdkDragAction old_action;    /* The last action we sent to the source */
+  GdkDragAction old_action;      /* The last action we sent to the source */
+  GdkDragAction old_actions;     /* The last actions we sent to the source */
+  GdkDragAction xdnd_actions;     /* What is currently set in XdndActionList */
 
   Window  dest_xid;
   guint xdnd_targets_set : 1;   /* Whether we've already set XdndTypeList */
-  guint xdnd_actions_set : 1;   /* Whether we've already set XdndActionsList */
+  guint xdnd_actions_set : 1;   /* Whether we've already set XdndActionList */
   guint xdnd_have_actions : 1; /* Whether an XdndActionList was provided */
   guint motif_targets_set : 1;  /* Whether we've already set motif initiator info */
   guint drag_status : 4;       /* current status of drag */
@@ -103,6 +105,10 @@ static GdkFilterReturn xdnd_drop_filter (GdkXEvent *xev,
                                         GdkEvent  *event,
                                         gpointer   data);
 
+static void   xdnd_manage_source_filter (GdkDragContext *context,
+                                        GdkWindow      *window,
+                                        gboolean        add_filter);
+
 /* Drag Contexts */
 
 static GList *contexts;
@@ -145,7 +151,13 @@ gdk_drag_context_unref (GdkDragContext *context)
       g_list_free (context->targets);
 
       if (context->source_window)
-       gdk_window_unref (context->source_window);
+       {
+         if ((context->protocol == GDK_DRAG_PROTO_XDND) &&
+             !context->is_source)
+           xdnd_manage_source_filter (context, context->source_window, FALSE);
+
+         gdk_window_unref (context->source_window);
+       }
 
       if (context->dest_window)
        gdk_window_unref (context->dest_window);
@@ -1361,11 +1373,12 @@ motif_send_motion (GdkDragContext  *context,
   MOTIF_XCLIENT_SHORT (&xev, 1) = motif_dnd_get_flags (context);
   MOTIF_XCLIENT_LONG (&xev, 1) = time;
 
-  if (context->suggested_action != private->old_action)
+  if ((context->suggested_action != private->old_action) ||
+      (context->actions != private->old_actions))
     {
       MOTIF_XCLIENT_BYTE (&xev, 0) = XmOPERATION_CHANGED;
 
-      private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT;
+      /* private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT; */
       retval = TRUE;
     }
   else
@@ -1724,7 +1737,8 @@ motif_drag_status (GdkEvent *event,
   if (context)
     {
       GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
-      if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
+      if ((private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT) ||
+         (private->drag_status == GDK_DRAG_STATUS_ACTION_WAIT))
        private->drag_status = GDK_DRAG_STATUS_DRAG;
       
       event->dnd.type = GDK_DRAG_STATUS;
@@ -2009,7 +2023,7 @@ xdnd_set_actions (GdkDragContext *context)
 
   if (!xdnd_actions_initialized)
     xdnd_initialize_actions();
-
+  
   actions = context->actions;
   n_atoms = 0;
   for (i=0; i<xdnd_n_actions; i++)
@@ -2042,6 +2056,7 @@ xdnd_set_actions (GdkDragContext *context)
                   (guchar *)atomlist, n_atoms);
 
   private->xdnd_actions_set = 1;
+  private->xdnd_actions = context->actions;
 }
 
 static void
@@ -2082,9 +2097,6 @@ xdnd_send_enter (GdkDragContext *context)
        }
     }
 
-  if (!private->xdnd_actions_set)
-    xdnd_set_actions (context);
-
   if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
                        FALSE, 0, &xev))
     {
@@ -2256,6 +2268,133 @@ xdnd_check_dest (Window win)
 
 /* Target side */
 
+static void
+xdnd_read_actions (GdkDragContext *context)
+{
+  Atom type;
+  int format;
+  gulong nitems, after;
+  Atom *data;
+
+  gint i;
+
+  gint old_warnings = gdk_error_warnings;
+
+  gdk_error_code = 0;
+  gdk_error_warnings = 0;
+
+  /* Get the XdndActionList, if set */
+
+  XGetWindowProperty (GDK_WINDOW_XDISPLAY (context->source_window),
+                     GDK_WINDOW_XWINDOW (context->source_window),
+                     gdk_atom_intern ("XdndActionList", FALSE), 0, 65536,
+                     False, XA_ATOM, &type, &format, &nitems,
+                     &after, (guchar **)&data);
+  
+  if (!gdk_error_code && (format == 32) && (type == XA_ATOM))
+    {
+      context->actions = 0;
+
+      for (i=0; i<nitems; i++)
+       context->actions |= xdnd_action_from_atom (data[i]);
+
+      ((GdkDragContextPrivate *)context)->xdnd_have_actions = TRUE;
+
+#ifdef G_ENABLE_DEBUG
+      if (gdk_debug_flags & GDK_DEBUG_DND)
+       {
+         GString *action_str = g_string_new (NULL);
+         if (context->actions & GDK_ACTION_MOVE)
+           g_string_append(action_str, "MOVE ");
+         if (context->actions & GDK_ACTION_COPY)
+           g_string_append(action_str, "COPY ");
+         if (context->actions & GDK_ACTION_LINK)
+           g_string_append(action_str, "LINK ");
+         if (context->actions & GDK_ACTION_ASK)
+           g_string_append(action_str, "ASK ");
+         
+         g_message("Xdnd actions = %s", action_str->str);
+         g_string_free (action_str, TRUE);
+       }
+#endif /* G_ENABLE_DEBUG */
+
+      XFree(data);
+    }
+
+  gdk_error_warnings = old_warnings;
+  gdk_error_code = 0;
+}
+
+/* We have to make sure that the XdndActionList we keep internally
+ * is up to date with the XdndActionList on the source window
+ * because we get no notification, because Xdnd wasn't meant
+ * to continually send actions. So we select on PropertyChangeMask
+ * and add this filter.
+ */
+static GdkFilterReturn 
+xdnd_source_window_filter (GdkXEvent *xev,
+                          GdkEvent  *event,
+                          gpointer   cb_data)
+{
+  XEvent *xevent = (XEvent *)xev;
+  GdkDragContext *context = cb_data;
+
+  if ((xevent->xany.type == PropertyNotify) &&
+      (xevent->xproperty.atom == gdk_atom_intern ("XdndActionList", FALSE)))
+    {
+      xdnd_read_actions (context);
+
+      return GDK_FILTER_REMOVE;
+    }
+
+  return GDK_FILTER_CONTINUE;
+}
+
+static void
+xdnd_manage_source_filter (GdkDragContext *context,
+                          GdkWindow      *window,
+                          gboolean        add_filter)
+{
+  gint old_warnings = 0;       /* quiet gcc */
+  GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+                              
+  gboolean is_foreign = (private->window_type == GDK_WINDOW_FOREIGN);
+
+  if (is_foreign)
+    {
+      old_warnings = gdk_error_warnings;
+      gdk_error_warnings = 0;
+    }
+
+  if (!private->destroyed)
+    {
+      if (add_filter)
+       {
+         gdk_window_set_events (window,
+                                gdk_window_get_events (window) |
+                                GDK_PROPERTY_CHANGE_MASK);
+         gdk_window_add_filter (window, xdnd_source_window_filter, context);
+
+       }
+      else
+       {
+         gdk_window_remove_filter (window,
+                                   xdnd_source_window_filter,
+                                   context);
+         /* Should we remove the GDK_PROPERTY_NOTIFY mask?
+          * but we might want it for other reasons. (Like
+          * INCR selection transactions).
+          */
+       }
+    }
+
+  if (is_foreign)
+    {
+      gdk_flush();
+      gdk_error_warnings = old_warnings;
+    }
+}
+
 static GdkFilterReturn 
 xdnd_enter_filter (GdkXEvent *xev,
                   GdkEvent  *event,
@@ -2339,49 +2478,14 @@ xdnd_enter_filter (GdkXEvent *xev,
                                                GUINT_TO_POINTER (xevent->xclient.data.l[2+i]));
     }
 
-  /* Get the XdndActionList, if set */
-
-  XGetWindowProperty (GDK_WINDOW_XDISPLAY (event->any.window), 
-                     source_window, 
-                     gdk_atom_intern ("XdndActionList", FALSE), 0, 65536,
-                     False, XA_ATOM, &type, &format, &nitems,
-                     &after, (guchar **)&data);
-  
-  if ((format == 32) && (type == XA_ATOM))
-    {
-      new_context->actions = 0;
-
-      for (i=0; i<nitems; i++)
-       new_context->actions |= xdnd_action_from_atom (data[i]);
-
-      ((GdkDragContextPrivate *)new_context)->xdnd_have_actions = TRUE;
-
-#ifdef G_ENABLE_DEBUG
-      if (gdk_debug_flags & GDK_DEBUG_DND)
-       {
-         GString *action_str = g_string_new (NULL);
-         if (new_context->actions & GDK_ACTION_MOVE)
-           g_string_append(action_str, "MOVE ");
-         if (new_context->actions & GDK_ACTION_COPY)
-           g_string_append(action_str, "COPY ");
-         if (new_context->actions & GDK_ACTION_LINK)
-           g_string_append(action_str, "LINK ");
-         if (new_context->actions & GDK_ACTION_ASK)
-           g_string_append(action_str, "ASK ");
-         
-         g_message("\tactions = %s", action_str->str);
-         g_string_free (action_str, TRUE);
-       }
-#endif /* G_ENABLE_DEBUG */
-
-      XFree(data);
-    }
-  
 #ifdef G_ENABLE_DEBUG
   if (gdk_debug_flags & GDK_DEBUG_DND)
     print_target_list (new_context->targets);
 #endif /* G_ENABLE_DEBUG */
 
+  xdnd_manage_source_filter (new_context, new_context->source_window, TRUE);
+  xdnd_read_actions (new_context);
+
   event->dnd.type = GDK_DRAG_ENTER;
   event->dnd.context = new_context;
   gdk_drag_context_ref (new_context);
@@ -2558,8 +2662,7 @@ gdk_drag_do_leave (GdkDragContext *context, guint32 time)
 
 GdkDragContext * 
 gdk_drag_begin (GdkWindow     *window,
-               GList         *targets,
-               GdkDragAction  actions)
+               GList         *targets)
 {
   GList *tmp_list;
   GdkDragContext *new_context;
@@ -2580,7 +2683,7 @@ gdk_drag_begin (GdkWindow     *window,
       tmp_list = tmp_list->prev;
     }
 
-  new_context->actions = actions;
+  new_context->actions = 0;
 
   return new_context;
 }
@@ -2717,13 +2820,25 @@ gdk_drag_motion (GdkDragContext *context,
                 GdkDragProtocol protocol,
                 gint            x_root, 
                 gint            y_root,
-                GdkDragAction   action,
+                GdkDragAction   suggested_action,
+                GdkDragAction   possible_actions,
                 guint32         time)
 {
   GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
 
   g_return_val_if_fail (context != NULL, FALSE);
 
+  /* When we have a Xdnd target, make sure our XdndActionList
+   * matches the current actions;
+   */
+  private->old_actions = context->actions;
+  context->actions = possible_actions;
+  
+  if ((protocol == GDK_DRAG_PROTO_XDND) &&
+      (!private->xdnd_actions_set ||
+       private->xdnd_actions != possible_actions))
+    xdnd_set_actions (context);
+
   if (context->dest_window != dest_window)
     {
       GdkEvent temp_event;
@@ -2754,8 +2869,9 @@ gdk_drag_motion (GdkDragContext *context,
            case GDK_DRAG_PROTO_NONE:
              break;
            }
-         private->old_action = action;
-         context->suggested_action = action;
+         private->old_action = suggested_action;
+         context->suggested_action = suggested_action;
+         private->old_actions = possible_actions;
        }
       else
        {
@@ -2782,7 +2898,7 @@ gdk_drag_motion (GdkDragContext *context,
   else
     {
       private->old_action = context->suggested_action;
-      context->suggested_action = action;
+      context->suggested_action = suggested_action;
     }
 
   /* Send a drag-motion event */
@@ -2797,11 +2913,11 @@ gdk_drag_motion (GdkDragContext *context,
          switch (context->protocol)
            {
            case GDK_DRAG_PROTO_MOTIF:
-             motif_send_motion (context, x_root, y_root, action, time);
+             motif_send_motion (context, x_root, y_root, suggested_action, time);
              break;
              
            case GDK_DRAG_PROTO_XDND:
-             xdnd_send_motion (context, x_root, y_root, action, time);
+             xdnd_send_motion (context, x_root, y_root, suggested_action, time);
              break;
 
            case GDK_DRAG_PROTO_ROOTWIN:
index 1c5efd714e278812f5e20d5ddea9b9101985b3cb..8ffdd2abf08cf46d5429e9ba7a2e3700be9eec8b 100644 (file)
@@ -58,6 +58,7 @@ struct _GtkDragSourceSite {
 struct _GtkDragSourceInfo {
   GtkWidget         *widget;
   GtkTargetList     *target_list; /* Targets for drag data */
+  GdkDragAction      possible_actions; /* Actions allowed by source */
   GdkDragContext    *context;    /* drag context */
   GtkWidget         *icon_window; /* Window for drag */
   GtkWidget         *ipc_widget;  /* GtkInvisible for grab, message passing */
@@ -145,9 +146,11 @@ static gint         default_icon_hot_x;
 static gint         default_icon_hot_y;
 
 /* Forward declarations */
-static GdkDragAction gtk_drag_get_event_action   (GdkEvent        *event, 
-                                                 gint             button,
-                                                 GdkDragAction    actions);
+static void gtk_drag_get_event_actions   (GdkEvent        *event, 
+                                         gint             button,
+                                         GdkDragAction    actions,
+                                         GdkDragAction   *suggested_action,
+                                         GdkDragAction   *possible_actions);
 static GdkCursor *   gtk_drag_get_cursor         (GdkDragAction action);
 static GtkWidget    *gtk_drag_get_ipc_widget     (void);
 static void          gtk_drag_release_ipc_widget (GtkWidget *widget);
@@ -391,9 +394,16 @@ gtk_drag_release_ipc_widget (GtkWidget *widget)
   drag_widgets = g_slist_prepend (drag_widgets, widget);
 }
 
-static GdkDragAction
-gtk_drag_get_event_action (GdkEvent *event, gint button, GdkDragAction actions)
+static void
+gtk_drag_get_event_actions (GdkEvent *event, 
+                           gint button, 
+                           GdkDragAction  actions,
+                           GdkDragAction *suggested_action,
+                           GdkDragAction *possible_actions)
 {
+  *suggested_action = 0;
+  *possible_actions = 0;
+
   if (event)
     {
       GdkModifierType state = 0;
@@ -422,32 +432,55 @@ gtk_drag_get_event_action (GdkEvent *event, gint button, GdkDragAction actions)
       }
       
       if (((button == 2) || (button == 3)) && (actions & GDK_ACTION_ASK))
-       return GDK_ACTION_ASK;
-      
-      if (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))
+       {
+         *suggested_action = GDK_ACTION_ASK;
+         *possible_actions = actions;
+       }
+      else if (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))
        {
          if ((state & GDK_SHIFT_MASK) && (state & GDK_CONTROL_MASK))
-           return (actions & GDK_ACTION_LINK) ? GDK_ACTION_LINK : 0;
+           {
+             if (actions & GDK_ACTION_LINK)
+               {
+                 *suggested_action = GDK_ACTION_LINK;
+                 *possible_actions = GDK_ACTION_LINK;
+               }
+           }
          else if (state & GDK_CONTROL_MASK)
-           return (actions & GDK_ACTION_COPY) ? GDK_ACTION_COPY : 0;
+           {
+             if (actions & GDK_ACTION_COPY)
+               {
+                 *suggested_action = GDK_ACTION_COPY;
+                 *possible_actions = GDK_ACTION_COPY;
+               }
+             return;
+           }
          else
-           return (actions & GDK_ACTION_MOVE) ? GDK_ACTION_MOVE : 0;
+           {
+             if (actions & GDK_ACTION_MOVE)
+               {
+                 *suggested_action = GDK_ACTION_MOVE;
+                 *possible_actions = GDK_ACTION_MOVE;
+               }
+             return;
+           }
        }
       else
        {
-         if ((state & (GDK_MOD1_MASK)) && (actions & GDK_ACTION_ASK))
-           return GDK_ACTION_ASK;
+         *possible_actions = actions;
 
-         if (actions & GDK_ACTION_COPY)
-           return GDK_ACTION_COPY;
+         if ((state & (GDK_MOD1_MASK)) && (actions & GDK_ACTION_ASK))
+           *suggested_action = GDK_ACTION_ASK;
+         else if (actions & GDK_ACTION_COPY)
+           *suggested_action =  GDK_ACTION_COPY;
          else if (actions & GDK_ACTION_MOVE)
-           return GDK_ACTION_MOVE;
+           *suggested_action = GDK_ACTION_MOVE;
          else if (actions & GDK_ACTION_LINK)
-           return GDK_ACTION_LINK;
+           *suggested_action = GDK_ACTION_LINK;
        }
     }
   
-  return 0;
+  return;
 }
 
 static GdkCursor *
@@ -1164,8 +1197,7 @@ gtk_drag_proxy_begin (GtkWidget *widget, GtkDragDestInfo *dest_info)
   source_info->widget = widget;
   gtk_widget_ref (source_info->widget);
   source_info->context = gdk_drag_begin (source_info->ipc_widget->window,
-                                        dest_info->context->targets, 
-                                        dest_info->context->actions);
+                                        dest_info->context->targets);
 
   source_info->target_list = gtk_target_list_new (NULL, 0);
   tmp_list = dest_info->context->targets;
@@ -1295,7 +1327,8 @@ gtk_drag_dest_motion (GtkWidget        *widget,
                       dest_window, proto,
                       current_event->dnd.x_root, 
                       current_event->dnd.y_root, 
-                      context->suggested_action, time);
+                      context->suggested_action, 
+                      context->actions, time);
 
       selection = gdk_drag_get_selection (info->proxy_source->context);
       if (selection && 
@@ -1411,7 +1444,8 @@ gtk_drag_dest_drop (GtkWidget          *widget,
                           dest_window, proto,
                           current_event->dnd.x_root, 
                           current_event->dnd.y_root, 
-                          context->suggested_action, time);
+                          context->suggested_action, 
+                          context->actions, time);
 
          selection = gdk_drag_get_selection (info->proxy_source->context);
          if (selection && 
@@ -1472,6 +1506,7 @@ gtk_drag_begin (GtkWidget         *widget,
   GList *targets = NULL;
   GList *tmp_list;
   guint32 time = GDK_CURRENT_TIME;
+  GdkDragAction possible_actions, suggested_action;
 
   g_return_val_if_fail (widget != NULL, NULL);
   g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL);
@@ -1498,8 +1533,7 @@ gtk_drag_begin (GtkWidget         *widget,
   info->widget = widget;
   gtk_widget_ref (info->widget);
   
-  info->context = gdk_drag_begin (info->ipc_widget->window,
-                                 targets, actions);
+  info->context = gdk_drag_begin (info->ipc_widget->window, targets);
   g_list_free (targets);
   
   g_dataset_set_data (info->context, "gtk-info", info);
@@ -1508,15 +1542,19 @@ gtk_drag_begin (GtkWidget         *widget,
   info->target_list = target_list;
   gtk_target_list_ref (target_list);
 
+  info->possible_actions = actions;
+
   info->cursor = NULL;
   info->status = GTK_DRAG_STATUS_DRAG;
   info->last_event = NULL;
   info->selections = NULL;
   info->icon_window = NULL;
+
+  gtk_drag_get_event_actions (event, info->button, actions,
+                             &suggested_action, &possible_actions);
   
   if (event)
-    info->cursor = gtk_drag_get_cursor (
-           gtk_drag_get_event_action (event, info->button, 0));
+    info->cursor = gtk_drag_get_cursor (suggested_action);
 
   gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_begin",
                           info->context);
@@ -2371,6 +2409,7 @@ gtk_drag_motion_cb (GtkWidget      *widget,
   GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
   GdkAtom selection;
   GdkDragAction action;
+  GdkDragAction possible_actions;
   GdkWindow *window = NULL;
   GdkWindow *dest_window;
   GdkDragProtocol protocol;
@@ -2383,9 +2422,10 @@ gtk_drag_motion_cb (GtkWidget      *widget,
       event->y_root = y_root;
     }
 
-  action = gtk_drag_get_event_action ((GdkEvent *)event, 
-                                     info->button, 
-                                     info->context->actions);
+  gtk_drag_get_event_actions ((GdkEvent *)event, 
+                             info->button, 
+                             info->possible_actions,
+                             &action, &possible_actions);
   
   info->cur_x = event->x_root - info->hot_x;
   info->cur_y = event->y_root - info->hot_y;
@@ -2402,7 +2442,8 @@ gtk_drag_motion_cb (GtkWidget      *widget,
                        &dest_window, &protocol);
 
   if (gdk_drag_motion (info->context, dest_window, protocol,
-                      event->x_root, event->y_root, action,
+                      event->x_root, event->y_root, action, 
+                      possible_actions,
                       event->time))
     {
       if (info->last_event)
@@ -2452,6 +2493,14 @@ gtk_drag_button_release_cb (GtkWidget      *widget,
 
   gdk_pointer_ungrab (event->time);
 
+  gtk_grab_remove (widget);
+  gtk_signal_disconnect_by_func (GTK_OBJECT (widget), 
+                                GTK_SIGNAL_FUNC (gtk_drag_button_release_cb),
+                                info);
+  gtk_signal_disconnect_by_func (GTK_OBJECT (widget), 
+                                GTK_SIGNAL_FUNC (gtk_drag_motion_cb),
+                                info);
+
   if ((info->context->action != 0) && (info->context->dest_window != NULL))
     {
       gtk_drag_drop (info, event->time);
@@ -2462,14 +2511,6 @@ gtk_drag_button_release_cb (GtkWidget      *widget,
       gtk_drag_drop_finished (info, FALSE, event->time);
     }
 
-  gtk_grab_remove (widget);
-  gtk_signal_disconnect_by_func (GTK_OBJECT (widget), 
-                                GTK_SIGNAL_FUNC (gtk_drag_button_release_cb),
-                                info);
-  gtk_signal_disconnect_by_func (GTK_OBJECT (widget), 
-                                GTK_SIGNAL_FUNC (gtk_drag_motion_cb),
-                                info);
-
   /* Send on a release pair to the the original 
    * widget to convince it to release its grab. We need to
    * call gtk_propagate_event() here, instead of